//
// Created by iris on 24-11-1.
//

#include "ASTGenerator/ASTGenerator.h"

#include "AST/AST.h"

#include "CLexer.h"

#include <optional>
#include <ranges>

using namespace ast;

using ExternDeclAndBlockItemRetType = std::variant<ASTBase *, vector<Declaration *> *>;

std::any ASTGenerator::visitBlockItem(CParser::BlockItemContext *ctx) {
    if (ctx->statement()) {
        // todo: assume visitStatement returns Statement*
        return ExternDeclAndBlockItemRetType(
            static_cast<ASTBase *>(std::any_cast<Statement *>(ctx->statement()->accept(this))));
    }

    return ExternDeclAndBlockItemRetType(std::any_cast<vector<Declaration *> *>(ctx->declaration()->accept(this)));
}


/**
 *
 * @param ctx
 * @return Expression*
 */
std::any ASTGenerator::visitPrimaryExpression(CParser::PrimaryExpressionContext *ctx) {
    if (ctx->IntegerConstant()) {
        return (Expression *) new ExpressionPrimary(std::stoi(ctx->IntegerConstant()->toString(), nullptr, 0));
        // return (ASTBase *) new ExpressionPrimary(std::stoi(ctx->IntegerConstant()->toString()));
    }
    if (ctx->FloatingConstant()) {
        return (Expression *) new ExpressionPrimary(std::stof(ctx->FloatingConstant()->toString()));
    }
    if (ctx->Identifier()) {
        return (Expression *) new ExpressionPrimary(ctx->Identifier()->toString());
    }
    if (ctx->LeftParen())
        return ctx->expression()->accept(this);
    unimplemented("other primary expression");
}

/**
 *
 * @param ctx
 * @return Expression*
 */
std::any ASTGenerator::visitPostfixExpression(CParser::PostfixExpressionContext *ctx) {
    if (ctx->postfixSuffix().empty()) {
        return ctx->primaryExpression()->accept(this);
    }
    // 只允许下标后缀嵌套
    assert(
        ctx->postfixSuffix().size() == 1 || std::ranges::all_of(ctx->postfixSuffix(), [](CParser::PostfixSuffixContext *
                ctx) {
            return ctx->LeftBracket();
            }));

    ASTOperator op;
    auto first = ctx->postfixSuffix().front();
    if (first->LeftBracket())
        op = ASTOperator::Subscript;
    else if (first->LeftParen())
        op = ASTOperator::FunctionCall;
    else if (first->PlusPlus())
        op = ASTOperator::PostPlusPlus;
    else
        op = ASTOperator::PostMinusMinus;

    vector<Expression *> exps;
    for (auto postfix: ctx->postfixSuffix()) {
        if (postfix->expression())
            exps.push_back(std::any_cast<Expression *>(postfix->expression()->accept(this)));
        else if (postfix->argumentExpressionList()) {
            auto res = postfix->argumentExpressionList()->assignmentExpression() | std::views::transform(
                           [this](CParser::AssignmentExpressionContext *assign_ctx) {
                               return std::any_cast<Expression *>(assign_ctx->accept(this));
                           });
            std::ranges::copy(res, std::back_inserter(exps));
        }
    }

    auto primary = dynamic_cast<ExpressionPrimary *>(std::any_cast<Expression
        *>(ctx->primaryExpression()->accept(this)));

    return (Expression *) new ExpressionPostfix(primary, op, exps);
}

std::any ASTGenerator::visitUnaryExpression(CParser::UnaryExpressionContext *ctx) {
    vector<ASTOperator> ops;
    for (const auto t: ctx->children) {
        if (t->getText() == "++")
            ops.push_back(ASTOperator::PlusPlus);
        else if (t->getText() == "--")
            ops.push_back(ASTOperator::MinusMinus);
        else if (t->getText() == "sizeof")
            ops.push_back(ASTOperator::Sizeof);
        else break;
    }

    if (ctx->postfixExpression()) {
        return (Expression *) new ExpressionUnary(
            std::any_cast<Expression *>(ctx->postfixExpression()->accept(this)),
            ops
        );
    }

    const auto op = ctx->unaryOperator();
    if (op->And())
        ops.push_back(ASTOperator::AddressOf);
    else if (op->Star())
        ops.push_back(ASTOperator::Deref);
    else if (op->Plus())
        ops.push_back(ASTOperator::Positive);
    else if (op->Minus())
        ops.push_back(ASTOperator::Negative);
    else if (op->Tilde())
        ops.push_back(ASTOperator::BitNot);
    else if (op->Not())
        ops.push_back(ASTOperator::Not);
    else unreachable("unknown unary operator: " + op->getText());

    return (Expression *) new ExpressionUnary(
        std::any_cast<Expression *>(ctx->castExpression()->accept(this)),
        ops
    );
}

// todo: avoid recursive calls
// 构造出来的ExpressionCast一定是类型转换分支
// 因为unary分支被直接返回了
std::any ASTGenerator::visitCastExpression(CParser::CastExpressionContext *ctx) {
    if (ctx->unaryExpression())
        return ctx->unaryExpression()->accept(this);

    if (ctx->castExpression()) {
        const auto type_name = ctx->typeName();
        if (type_name->abstractDeclarator() != nullptr)
            unimplemented("cast to pointer type");

        optional<type::ASTType> cast_to_type = std::nullopt;
        auto specifier_qualifier_list = type_name->specifierQualifierList();
        while (specifier_qualifier_list != nullptr) {
            if (specifier_qualifier_list->typeQualifier()) {
                // ignore const
                continue;
            }
            if (cast_to_type)
                unreachable("multiple type in specifier_qualifier_list");
            cast_to_type = Helper::getType(specifier_qualifier_list->typeSpecifier());
            specifier_qualifier_list = specifier_qualifier_list->specifierQualifierList();
        }

        return (Expression *) new ExpressionCast(std::any_cast<Expression *>(ctx->castExpression()->accept(this)),
                                                 cast_to_type.value());
    }

    unreachable("digital sequence in cast expression");
}

std::any ASTGenerator::visitMultiplicativeExpression(CParser::MultiplicativeExpressionContext *ctx) {
    auto base = std::any_cast<Expression *>(ctx->children[0]->accept(this));
    vector<pair<ASTOperator, Expression *> > others;
    assert(ctx->children.size() % 2 == 1);
    for (int i = 1; i < ctx->children.size(); i += 2) {
        ASTOperator op;
        const auto &op_str = ctx->children[i]->getText();
        if (op_str == "*") op = ASTOperator::Times;
        else if (op_str == "/") op = ASTOperator::Div;
        else op = ASTOperator::Mod;

        others.emplace_back(op, std::any_cast<Expression *>(ctx->children[i + 1]->accept(this)));
    }
    return (Expression *) new ExpressionMultiplicative(base, others);
}

std::any ASTGenerator::visitAdditiveExpression(CParser::AdditiveExpressionContext *ctx) {
    auto base = std::any_cast<Expression *>(ctx->children[0]->accept(this));
    vector<pair<ASTOperator, Expression *> > others;
    assert(ctx->children.size() % 2 == 1);
    for (int i = 1; i < ctx->children.size(); i += 2) {
        ASTOperator op;
        const auto &op_str = ctx->children[i]->getText();
        if (op_str == "+") op = ASTOperator::Add;
        else op = ASTOperator::Sub;

        others.emplace_back(op, std::any_cast<Expression *>(ctx->children[i + 1]->accept(this)));
    }
    return (Expression *) new ExpressionAdditive(base, others);
}

std::any ASTGenerator::visitShiftExpression(CParser::ShiftExpressionContext *ctx) {
    auto base = std::any_cast<Expression *>(ctx->children[0]->accept(this));
    vector<pair<ASTOperator, Expression *> > others;
    assert(ctx->children.size() % 2 == 1);
    for (int i = 1; i < ctx->children.size(); i += 2) {
        ASTOperator op;
        const auto &op_str = ctx->children[i]->getText();
        if (op_str == "<<") op = ASTOperator::LeftShift;
        else op = ASTOperator::Sub;

        others.emplace_back(op, std::any_cast<Expression *>(ctx->children[i + 1]->accept(this)));
    }
    return (Expression *) new ExpressionShift(base, others);
}

std::any ASTGenerator::visitRelationalExpression(CParser::RelationalExpressionContext *ctx) {
    auto base = std::any_cast<Expression *>(ctx->children[0]->accept(this));
    vector<pair<ASTOperator, Expression *> > others;
    assert(ctx->children.size() % 2 == 1);
    for (int i = 1; i < ctx->children.size(); i += 2) {
        ASTOperator op;
        const auto &op_str = ctx->children[i]->getText();
        if (op_str == "<") op = ASTOperator::Less;
        else if (op_str == "<=") op = ASTOperator::LessEqual;
        else if (op_str == ">") op = ASTOperator::Greater;
        else op = ASTOperator::GreaterEqual;

        others.emplace_back(op, std::any_cast<Expression *>(ctx->children[i + 1]->accept(this)));
    }
    return (Expression *) new ExpressionRelational(base, others);
}

std::any ASTGenerator::visitEqualityExpression(CParser::EqualityExpressionContext *ctx) {
    auto base = std::any_cast<Expression *>(ctx->children[0]->accept(this));
    vector<pair<ASTOperator, Expression *> > others;
    assert(ctx->children.size() % 2 == 1);
    for (int i = 1; i < ctx->children.size(); i += 2) {
        ASTOperator op;
        const auto &op_str = ctx->children[i]->getText();
        if (op_str == "==") op = ASTOperator::Equal;
        else op = ASTOperator::NotEqual;

        others.emplace_back(op, std::any_cast<Expression *>(ctx->children[i + 1]->accept(this)));
    }
    return (Expression *) new ExpressionEquality(base, others);
}

std::any ASTGenerator::visitAndExpression(CParser::AndExpressionContext *ctx) {
    vector<Expression *> exps;
    assert(ctx->children.size() % 2 == 1);

    for (int i = 0; i < ctx->children.size(); i += 2) {
        exps.push_back(
            std::any_cast<Expression *>(ctx->children[i]->accept(this))
        );
    }

    return (Expression *) new ExpressionAnd(exps);
}

std::any ASTGenerator::visitExclusiveOrExpression(CParser::ExclusiveOrExpressionContext *ctx) {
    vector<Expression *> exps;
    assert(ctx->children.size() % 2 == 1);

    for (int i = 0; i < ctx->children.size(); i += 2) {
        exps.push_back(
            std::any_cast<Expression *>(ctx->children[i]->accept(this))
        );
    }

    return (Expression *) new ExpressionExclusiveOr(exps);
}

std::any ASTGenerator::visitInclusiveOrExpression(CParser::InclusiveOrExpressionContext *ctx) {
    vector<Expression *> exps;
    assert(ctx->children.size() % 2 == 1);

    for (int i = 0; i < ctx->children.size(); i += 2) {
        exps.push_back(
            std::any_cast<Expression *>(ctx->children[i]->accept(this))
        );
    }

    return (Expression *) new ExpressionInclusiveOr(exps);
}

std::any ASTGenerator::visitLogicalAndExpression(CParser::LogicalAndExpressionContext *ctx) {
    vector<Expression *> exps;
    assert(ctx->children.size() % 2 == 1);

    for (int i = 0; i < ctx->children.size(); i += 2) {
        exps.push_back(
            std::any_cast<Expression *>(ctx->children[i]->accept(this))
        );
    }

    return (Expression *) new ExpressionLogicalAnd(exps);
}

std::any ASTGenerator::visitLogicalOrExpression(CParser::LogicalOrExpressionContext *ctx) {
    vector<Expression *> exps;
    assert(ctx->children.size() % 2 == 1);

    for (int i = 0; i < ctx->children.size(); i += 2) {
        exps.push_back(
            std::any_cast<Expression *>(ctx->children[i]->accept(this))
        );
    }

    return (Expression *) new ExpressionLogicalOr(exps);
}

std::any ASTGenerator::visitConditionalExpression(CParser::ConditionalExpressionContext *ctx) {
    if (ctx->children.size() > 1) {
        return (Expression *) new ExpressionConditional(
            std::any_cast<Expression *>(ctx->logicalOrExpression()->accept(this)),
            std::any_cast<Expression *>(ctx->expression()->accept(this)),
            std::any_cast<Expression *>(ctx->conditionalExpression()->accept(this))
        );
    }

    return (Expression *) new ExpressionConditional(
        std::any_cast<Expression *>(ctx->logicalOrExpression()->accept(this)), nullptr, nullptr);
}

// todo: avoid recursive calls
std::any ASTGenerator::visitAssignmentExpression(CParser::AssignmentExpressionContext *ctx) {
    if (ctx->DigitSequence())
        unimplemented("digital sequence for assignment expression");

    Expression *base;
    if (ctx->conditionalExpression()) {
        base = std::any_cast<Expression *>(ctx->conditionalExpression()->accept(this));
        return (Expression *) new ExpressionAssignment(base, {});
    }

    base = std::any_cast<Expression *>(ctx->unaryExpression()->accept(this));
    return (Expression *) new ExpressionAssignment(base, pair{
                                                       Helper::getAssignOperator(ctx->assignmentOperator()),
                                                       std::any_cast<Expression *>(
                                                           ctx->assignmentExpression()->accept(this))
                                                   });


    // std::deque<pair<ASTOperator, Expression *> > others;
    //
    // auto next = ctx->assignmentExpression();
    // while (next->assignmentExpression())
    //     next = next->assignmentExpression();
    // assert(next->conditionalExpression());
    // next = dynamic_cast<CParser::AssignmentExpressionContext *>(next->parent);
    // assert(next);
    //
    // while (next->parent != ctx) {
    //     others.emplace_front(Helper::getAssignOperator())
    // }
}

std::any ASTGenerator::visitDeclaration(CParser::DeclarationContext *ctx) {
    auto decls = new vector<Declaration *>;

    optional<type::ASTType> type;
    bool isConst = false;
    for (const auto specifier: ctx->declarationSpecifiers()->declarationSpecifier()) {
        assert(!specifier->storageClassSpecifier() && !specifier->functionSpecifier());
        // ignore const
        if (specifier->typeQualifier()) {
            isConst = true;
            continue;
        }

        if (type) {
            // for decls like "int value";
            // antlr thinks "value" here should be typedef name
            if (specifier->typeSpecifier()->typedefName()) {
                decls->push_back(
                    new DeclarationBuiltinType(specifier->typeSpecifier()->typedefName()->getText(), type.value(),
                                               {}, nullptr, isConst)
                );
            }
            return decls;
        }

        type = Helper::getType(specifier->typeSpecifier());
    }

    for (const auto decl: ctx->initDeclaratorList()->initDeclarator()) {
        auto declarator = decl->declarator();
        auto initializer = decl->initializer();

        if (declarator->pointer())
            unimplemented("declaration of pointers");

        auto d_declarator = declarator->directDeclarator();
        vector<Expression *> dimensions;
        while (!d_declarator->Identifier()) {
            assert(!d_declarator->declarator());
            dimensions.insert(dimensions.begin(),
                              d_declarator->assignmentExpression()
                                  ? std::any_cast<Expression *>(d_declarator->assignmentExpression()->accept(this))
                                  : nullptr
            );
            d_declarator = d_declarator->directDeclarator();
        }

        decls->push_back(
            new DeclarationBuiltinType(d_declarator->Identifier()->getText(), type.value(), dimensions,
                                       initializer ? any_cast<Expression *>(initializer->accept(this)) : nullptr,
                                       isConst)
        );
    }

    return decls;
}

std::any ASTGenerator::visitSelectionStatement(CParser::SelectionStatementContext *ctx) {
    if (ctx->Switch())
        unimplemented("switch statement.");
    auto cond = std::any_cast<Expression *>(ctx->expression()->accept(this));
    auto if_branch = std::any_cast<Statement *>(ctx->statement()[0]->accept(this));
    auto else_branch = ctx->Else() ? std::any_cast<Statement *>(ctx->statement()[1]->accept(this)) : nullptr;
    return (Statement *) new StatementIfElse(cond, if_branch, else_branch);
}

std::any ASTGenerator::visitStatement(CParser::StatementContext *ctx) {
    if (ctx->selectionStatement())
        return ctx->selectionStatement()->accept(this);
    if (ctx->jumpStatement())
        return ctx->jumpStatement()->accept(this);
    if (ctx->compoundStatement())
        return ctx->compoundStatement()->accept(this);
    if (ctx->expressionStatement())
        return ctx->expressionStatement()->accept(this);
    if (ctx->iterationStatement())
        return ctx->iterationStatement()->accept(this);
    else
        unimplemented("statement: " + ctx->getText());
}

std::any ASTGenerator::visitIterationStatement(CParser::IterationStatementContext *ctx) {
    if (ctx->While()) {
        auto cond = std::any_cast<Expression *>(ctx->expression()->accept(this));
        auto statement = std::any_cast<Statement *>(ctx->statement()->accept(this));
        return (Statement *) new StatementWhile(cond, statement);
    }
    unimplemented("iteration statement: " + ctx->getText());
}


std::any ASTGenerator::visitCompoundStatement(CParser::CompoundStatementContext *ctx) {
    // std::cout << __PRETTY_FUNCTION__ << std::endl;


    auto items = std::vector<ASTBase *>{};
    if (ctx->blockItemList() == nullptr) {
        warn("No items in compound statement.");
        return (Statement *) new StatementCompound(items);
    }


    for (const auto &item: ctx->blockItemList()->blockItem()) {
        auto ret = std::any_cast<ExternDeclAndBlockItemRetType>(item->accept(this));

        if (std::holds_alternative<ASTBase *>(ret))
            items.emplace_back(std::get<ASTBase *>(ret));
        else {
            auto decls = std::get<vector<Declaration *> *>(ret);
            items.insert(items.end(), decls->begin(), decls->end());
            delete decls;
        }
    }

    return (Statement *) new StatementCompound(items);
}

std::any ASTGenerator::visitFunctionDefinition(CParser::FunctionDefinitionContext *ctx) {
    if (ctx->declarationSpecifiers() == nullptr) {
        unreachable("Function ret type not found.");
    }

    if (ctx->declarationList() != nullptr) {
        unreachable("Function not allowed to be defined in a list.");
    }


    auto specifiers = ctx->declarationSpecifiers();
    auto declarator = ctx->declarator();
    auto pointer_depth = declarator->pointer() ? declarator->pointer()->children.size() : 0;

    if (pointer_depth != 0) {
        unimplemented("function returning pointers");
    }

    // ret type
    std::optional<type::ASTType> return_type = std::nullopt;
    for (const auto specifier: specifiers->declarationSpecifier()) {
        if (auto storage_class = specifier->storageClassSpecifier(); storage_class != nullptr) {
            if (storage_class->Typedef()) {
                unreachable("typedef before function definition.");
            }
            // ignore static and extern
        }
        // ignore const and inline
        if (auto type_specifier = specifier->typeSpecifier(); type_specifier != nullptr) {
            return_type = Helper::getType(type_specifier);
        }
    }

    std::string name = declarator->directDeclarator()->directDeclarator()->Identifier()->toString();
    vector<DeclarationBuiltinType *> params;
    if (declarator->directDeclarator()->parameterTypeList()) {
        // function with params
        for (auto param: declarator->directDeclarator()->parameterTypeList()->parameterList()->parameterDeclaration()) {
            auto param_specifiers = param->declarationSpecifiers();
            auto param_declarator = param->declarator();
            assert(param_declarator->pointer() == nullptr);

            std::optional<type::ASTType> param_type = std::nullopt;
            bool param_is_const = false;
            for (const auto specifier: param_specifiers->declarationSpecifier()) {
                if (auto storage_class = specifier->storageClassSpecifier(); storage_class != nullptr) {
                    if (storage_class->Typedef()) {
                        unreachable("typedef before function params.");
                    }
                    // ignore static and extern
                }
                if (auto type_qualifier = specifier->typeQualifier(); type_qualifier != nullptr) {
                    assert(type_qualifier->Const());
                    param_is_const = true;
                }
                if (auto type_specifier = specifier->typeSpecifier(); type_specifier != nullptr) {
                    param_type = Helper::getType(type_specifier);
                }
            }

            vector<Expression *> dimensions;
            auto param_d_declarator = param_declarator->directDeclarator();
            while (!param_d_declarator->Identifier()) {
                assert(!param_d_declarator->declarator());
                dimensions.insert(dimensions.begin(),
                                  param_d_declarator->assignmentExpression()
                                      ? std::any_cast<Expression *>(
                                          param_d_declarator->assignmentExpression()->accept(this))
                                      : nullptr
                );
                param_d_declarator = param_d_declarator->directDeclarator();
            }
            const string &param_name = param_d_declarator->Identifier()->getText();

            params.push_back(
                new DeclarationBuiltinType(param_name, param_type.value(), dimensions, nullptr, param_is_const));
        }
    }

    auto content = dynamic_cast<StatementCompound *>(std::any_cast<Statement
        *>(ctx->compoundStatement()->accept(this)));


    return new DeclarationFunction(name, return_type.value(), params, content);
}

std::any ASTGenerator::visitCompilationUnit(CParser::CompilationUnitContext *ctx) {
    if (ctx->translationUnit() == nullptr) {
        unreachable("no translation unit found.");
    }

    return ctx->translationUnit()->accept(this);
}

std::any ASTGenerator::visitJumpStatement(CParser::JumpStatementContext *ctx) {
    if (ctx->Return()) {
        if (auto exp = ctx->expression(); exp != nullptr) {
            assert(exp->assignmentExpression().size() == 1);
        }


        if (ctx->expression()) {
            auto ret_value = ctx->expression()->accept(this);
            return (Statement *) new StatementReturn(std::any_cast<Expression *>(ret_value));
        } else
            return (Statement *) new StatementReturn(nullptr);
    }

    if (ctx->Break())
        return (Statement *) new StatementBreak();
    if (ctx->Continue())
        return (Statement *) new StatementContinue();
    unimplemented("jump statement except return, break");
}

std::any ASTGenerator::visitExpressionStatement(CParser::ExpressionStatementContext *ctx) {
    return (Statement *) new StatementExpression(ctx->expression()
                                                     ? std::any_cast<Expression *>(ctx->expression()->accept(this))
                                                     : nullptr);
}

std::any ASTGenerator::visitTranslationUnit(CParser::TranslationUnitContext *ctx) {
    auto decls = new std::vector<ASTBase *>{};
    for (const auto decl: ctx->externalDeclaration()) {
        auto res = std::any_cast<ExternDeclAndBlockItemRetType>(decl->accept(this));
        // decls->emplace_back(std::any_cast<ASTBase *>(res));
        if (std::holds_alternative<ASTBase *>(res)) {
            decls->emplace_back(std::get<ASTBase *>(res));
        } else {
            const auto &declarations = std::get<vector<Declaration *> *>(res);
            decls->insert(decls->end(), declarations->begin(), declarations->end());
        }
    }
    return decls;
}

std::any ASTGenerator::visitExternalDeclaration(CParser::ExternalDeclarationContext *ctx) {
    ExternDeclAndBlockItemRetType res = static_cast<ASTBase *>(nullptr);
    if (ctx->functionDefinition()) {
        auto func = ctx->functionDefinition()->accept(this);
        auto func_ptr = std::any_cast<DeclarationFunction *>(func);
        res = dynamic_cast<ASTBase *>(func_ptr);
    } else {
        res = std::any_cast<vector<Declaration *> *>(ctx->declaration()->accept(this));
    }
    return res;
}

std::any ASTGenerator::visitInitializer(CParser::InitializerContext *ctx) {
    if (ctx->assignmentExpression())
        return ctx->assignmentExpression()->accept(this);

    // initializer list branch
    auto list = ctx->initializerList();
    vector<Expression *> elements;
    if (!list)
        return (Expression *) new ExpressionInitializerList(elements);
    assert(list->designation().empty());
    for (auto initializer: list->initializer())
        elements.push_back(std::any_cast<Expression *>(initializer->accept(this)));
    return (Expression *) new ExpressionInitializerList(elements);
}


void run_antlr(const std::string &src) {
    ASTGenerator mcv;
    antlr4::ANTLRInputStream input(src);
    CLexer lexer(&input);
    antlr4::CommonTokenStream tokens(&lexer);
    CParser parser(&tokens);
    auto res = mcv.visitCompilationUnit(parser.compilationUnit());
    auto ptr = std::any_cast<std::vector<ASTBase *> *>(res);
    root = ptr;
}

type::ASTType ASTGenerator::Helper::getType(CParser::TypeSpecifierContext *ctx) {
    if (ctx->Int())
        return type::getInt();
    if (ctx->Float())
        return type::getFloat();
    if (ctx->Void())
        return type::getVoid();
    unimplemented("user defined types: struct, enum, union");
}

ast::ASTOperator ASTGenerator::Helper::getAssignOperator(CParser::AssignmentOperatorContext *ctx) {
    if (ctx->Assign())
        return ASTOperator::Assign;
    if (ctx->StarAssign())
        return ASTOperator::MulAssign;
    if (ctx->DivAssign())
        return ASTOperator::DivAssign;
    if (ctx->ModAssign())
        return ASTOperator::ModAssign;
    if (ctx->PlusAssign())
        return ASTOperator::AddAssign;
    if (ctx->MinusAssign())
        return ASTOperator::SubAssign;
    if (ctx->LeftShiftAssign())
        return ASTOperator::LeftShiftAssign;
    if (ctx->RightShiftAssign())
        return ASTOperator::RightShiftAssign;
    if (ctx->AndAssign())
        return ASTOperator::BitAndAssign;
    if (ctx->XorAssign())
        return ASTOperator::BitXorAssign;
    if (ctx->OrAssign())
        return ASTOperator::BitOrAssign;

    unreachable("no such assign operator: " + ctx->getText());
}
